/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package controleur;

import ia_multiagent1.Agent;
import ia_multiagent1.Espace2D;
import ia_multiagent1.LogAgent;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import vue.InterfacePrincipaleFrame;
import vue.Notice8JFrame;




/**
 *
 * @author Harakan
 */
public class Controleur implements Runnable{
    
    private static Controleur controleur;
    
    private static InterfacePrincipaleFrame IPF;
    private static Espace2D E2D;
    private static Vector<Agent> mesAgents;
    private static int dimGrille = 50;
    private static int nbRessources = 650; 
    private static int nbAgent = 50; 
    private static int time=0;
    private static boolean priseRessources = true;
    private static boolean ressourcesPerissables = false;
    private static int maxlife = 100;
    
    private static boolean pause;
    private static boolean stop;

    
    
    Notice8JFrame maNotice8Frame;
    private static boolean champAttractifActif = false;
    private static boolean presencePheromones = false;
    private static boolean disparitionPheromone = true;
    private static boolean onlyValeurChamps = false;    
    private static boolean pheromoneAsPointAttraction = false;
    private static int dureeViePheromone = 100;
    private static boolean continueSimu = true;
    
    private static int delai = 50;
    private static int nbStep = 10000;

    public static boolean isContinueSimu() {
        return continueSimu;
    }

    public static void setContinueSimu(boolean continueSimu) {
        Controleur.continueSimu = continueSimu;
    }

    
    
    public static void setPheromoneAsPointAttraction(boolean pheromoneAsPointAttraction) {
        Controleur.pheromoneAsPointAttraction = pheromoneAsPointAttraction;
    }
    
    
    public static void setDisparitionPheromone(boolean disparitionPheromone) {
        Controleur.disparitionPheromone = disparitionPheromone;
    }

    public void setChampAtrtactifActif(boolean champAtrtactifActif) {
        Controleur.champAttractifActif = champAtrtactifActif;
    }
    public static void setPriseRessources(boolean priseRessources) {
        Controleur.priseRessources = priseRessources;
    }
    
    public void setPresencePheromones(boolean presencePheromones) {
        Controleur.presencePheromones = presencePheromones;
    }

    //private Agent monAgent;
    
    public static void placerRessourcesAleatoirement(int n){
        int k=0;
        boolean caseVide = false;

        
        while (k<n){
            //System.out.print("placement ressource number : "+k);
            
            int abs = 0;
            int ord = 0;
            while (!caseVide){ //tant qu'on a pas choisit une case vide, on rechoisit une case.. TTT moyen optimiser ca !
                //System.out.print("case vide recherche");
                abs = (int) Math.floor(dimGrille*Math.random()); //renvoie un nombre aléatoire entre 0 et dimGrille           
                //test
                if (abs >= dimGrille || abs < 0){
                    System.err.print("ERROR");
                }
                ord = (int) Math.floor(dimGrille*Math.random()); //renvoie un nombre aléatoire entre 0 et dimGrille
            
                //test
                if (abs >= dimGrille || abs < 0){
                    System.err.println("ERROR");
                }  
                caseVide = E2D.estVide(abs,ord);
            }
                       
            if (nbRessources > dimGrille*dimGrille){
                System.err.println("ERROR 2");
                System.exit(0);
            }
            int ressourceType = (int) Math.floor(3*Math.random()+1); //renvoie un nombre aléatoire entre 1 et 3           
            //test
            if (ressourceType > 3 || ressourceType <= 0){
                System.err.println("ERROR");
            }
            
            //PLACER RESSOURCE DANS LA CASE
            if (ressourcesPerissables){
                // Durée de vie de la nouvelle ressource
                int life = (int) Math.floor(maxlife*Math.random()+1);
                E2D.setCase(abs, ord, ressourceType, life);
            }
            else{
                E2D.setCase(abs, ord, ressourceType);
            }
                
            k++;
            caseVide = false;
        }
    }

    
    public static void replacerRessources(int type, int q){
        int k=0;
        boolean caseVide = false;
        while (k<q){
            //System.out.print("placement ressource number : "+k);
            
            int abs = 0;
            int ord = 0;
            while (!caseVide){ //tant qu'on a pas choisit une case vide, on rechoisit une case.. TTT moyen optimiser ca !
                //System.out.print("case vide recherche");
                abs = (int) Math.floor(dimGrille*Math.random()); //renvoie un nombre aléatoire entre 0 et dimGrille           
                //test
                if (abs >= dimGrille || abs < 0){
                    System.err.print("ERROR");
                }
                ord = (int) Math.floor(dimGrille*Math.random()); //renvoie un nombre aléatoire entre 0 et dimGrille
            
                //test
                if (abs >= dimGrille || abs < 0){
                    System.err.println("ERROR");
                }  
                caseVide = E2D.estVide(abs,ord);
            }
                       
            if (nbRessources > dimGrille*dimGrille){
                System.err.println("ERROR 2");
                System.exit(0);
            }         
            //test
            if (type > 3 || type <= 0){
                System.err.println("ERROR");
            }
            
            // Durée de vie de la nouvelle ressource
            int life = (int) Math.floor(maxlife*Math.random()+1);
            
            //PLACER RESSOURCE DANS LA CASE
            E2D.setCase(abs, ord, type, life);
            
            k++;
            caseVide = false;
        }
    }
    
    public static void init(){     
        //init grille 
        E2D = new Espace2D(dimGrille, nbRessources);
         
        if (champAttractifActif){
            E2D.setChampAttractifDroite();
        }
 
        
        
        
        mesAgents = initAgent(nbAgent);  
        
        IPF = new InterfacePrincipaleFrame(dimGrille, mesAgents, E2D, onlyValeurChamps, presencePheromones);
        
             
        //init ressources TTT(possibilité optimiser...)
        placerRessourcesAleatoirement(nbRessources);
        
        //E2D.print();
       
    }
    
    
    private static int[] majRessources() {
        int[] res = new int[3];
        for(int i=0; i<dimGrille; i++){
            for(int j=0; j<dimGrille; j++){
                int k = E2D.getCase(i, j).majRessource();
                if (k!=0){
                    res[k-1]++;
                }
            }
        }
        return res;
    }
    
    public static void reinit(int nbAgents, int nbRessources, boolean priseRessources,
                              int nbStep, int delai, boolean ephemeres, boolean champAttractif,
                              boolean enablePheromones, boolean disparitionPheromones,
                              int lifePheromones, boolean pheromonesAttractives){
        
        IPF.setVisibleGrid(false);
        
        Controleur.nbRessources = nbRessources;
        Controleur.priseRessources = priseRessources;
        Controleur.nbStep = nbStep;
        Controleur.delai = delai;
        Controleur.ressourcesPerissables = ephemeres;
        Controleur.champAttractifActif = champAttractif;
        Controleur.presencePheromones = enablePheromones;
        Controleur.dureeViePheromone = lifePheromones;
        Controleur.disparitionPheromone = disparitionPheromones;
        Controleur.pheromoneAsPointAttraction = pheromonesAttractives;

        
                //init grille 
        E2D = new Espace2D(dimGrille, nbRessources);
        
        if (champAttractifActif){
            E2D.setChampAttractifDroite();
        }
        
        mesAgents = initAgent(nbAgents);
        IPF.reInit(dimGrille, mesAgents, E2D, onlyValeurChamps, presencePheromones);
        IPF.setVisibleGrid(true);
        
             
        //init ressources TTT(possibilité optimisation...)(pourquoi? marche pas mal...)
        placerRessourcesAleatoirement(nbRessources);
        
        //E2D.print();    
    }

    private static Vector<Agent> initAgent(int k) {
        Vector<Agent> agents = new Vector<Agent>();
        while(k!=0){
            int x = (int) Math.floor(dimGrille*Math.random());
            int y = (int) Math.floor(dimGrille*Math.random());
            agents.add(new Agent(x, y, dimGrille, E2D, dureeViePheromone, disparitionPheromone, presencePheromones));
            k--;
        }
        return agents;
    }
    
    public static Vector<Agent> initAgents(int nb, int i, int j){
        Vector<Agent> agents = new Vector<Agent>();
        while(nb!=0){
            agents.add(new Agent(i, j, dimGrille, E2D, dureeViePheromone, disparitionPheromone, presencePheromones));
            nb--;
        }
        return agents;
    }
    
    public void initAvecChampAttractionLineaire() {
        //init grille 
        E2D = new Espace2D(dimGrille, nbRessources);
        E2D.setChampAttractifDroite();
        mesAgents = new Vector<Agent>();   
        mesAgents.add(new Agent(10, 15,dimGrille, E2D,dureeViePheromone,disparitionPheromone, presencePheromones)); 
        boolean suiviAgent = true;
        boolean valeurChamps = true;
        maNotice8Frame = new Notice8JFrame(dimGrille,mesAgents,E2D,valeurChamps,suiviAgent);               
    }
        
        
   /* public  void runAvecChampAtraction(){
        System.out.println("run lancee");
        int t=1;
        while (t<=10){                    
            try {
                Thread.sleep(200);
           } catch (InterruptedException ex) {
                Logger.getLogger(Espace2D.class.getName()).log(Level.SEVERE, null, ex);
           }
            step(false, true);  // pour l'instant pas de prise de ressources, mais avec un champ attractif.
            maNotice8Frame.repaintGrille();              
            t++;
        }
        System.out.println(mesAgents.elementAt(1).getHistoire());
     }
    
    */
    
     public static void step(boolean champAttractif){
      //  System.out.println("##################### Enetring in step");
        time++;
        for (int i=0; i<mesAgents.size(); i++){
            Agent monAgent = mesAgents.elementAt(i);
                
            if (priseRessources){
                //System.out.println("PriseRessourceOK");
                if (!monAgent.poseRessource() && !monAgent.priseRessource()){
                    if (champAttractif){
                        try {
                            monAgent.moveAttraction();
                        } catch (Exception ex) {
                            Logger.getLogger(Controleur.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                    else{
                        monAgent.moveAleatoire();
                    }                       
                }
            }       
            else{
                if (champAttractif){
                    try {
                        monAgent.moveAttraction();
                    } catch (Exception ex) {
                        Logger.getLogger(Controleur.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                else{                         
//                    System.out.println("1 -***********************************");
//                    System.out.println(" taille vect = "+ monAgent.getPheromones().size());
//                    System.out.println("vecteur pheromone agent = " + monAgent.convertStringForLiveRemaining());                    
                    monAgent.moveAleatoire();
//                    System.out.println("taille new vect = "+ monAgent.getPheromones().size());
//                    System.out.println("vecteur pheromone agent = " + monAgent.convertStringForLiveRemaining());
//                    System.out.println("2 -***********************************");                    
                }
            }
            
            monAgent.updateLog(time);
  
            
        }
        
        // BBB ici mise à jour des ressources
        if (ressourcesPerissables){
            int[] reaffect = majRessources();
            replacerRessources(1, reaffect[0]);
            replacerRessources(2, reaffect[1]);
            replacerRessources(3, reaffect[2]);
        }
        
        if (pheromoneAsPointAttraction){
            E2D.setMesPointsAttraction(E2D.getMesPointsAttractionFonctionPheromones());
        }
        
     //   System.out.println("#####################End of the current step");    
    }
            
        
   public  void run(){     
        int t=1;
        
        while (t<=nbStep && continueSimu){

        
           // System.out.println(" *** t = " + t + "***");
            try {

                Thread.sleep(delai);

            } catch (InterruptedException ex) {
                Logger.getLogger(Espace2D.class.getName()).log(Level.SEVERE, null, ex);
            }


//            if (champAttractifActif){
//                System.out.println("demande une step, champsAttractif"); 
//            }
            
            
                step(champAttractifActif);
               // maNotice8Frame.repaintGrille();
                IPF.repaintGrille(); 
   
            
           // System.out.println(" *** fin de t = " + t + "***");  
            t++;
        }

       /* System.out.println(mesAgents.elementAt(0).getHistoire());
        
        System.out.println("R1 autour : "+mesAgents.elementAt(0).capteur(1));
        System.out.println("R2 autour : "+mesAgents.elementAt(0).capteur(2));
        System.out.println("R3 autour : "+mesAgents.elementAt(0).capteur(3));
        System.out.println("R1 rencontrés : "+mesAgents.elementAt(0).getBucketR1());
        System.out.println("R2 rencontrés : "+mesAgents.elementAt(0).getBucketR2());
        System.out.println("R3 rencontrés : "+mesAgents.elementAt(0).getBucketR3());*/

        
    }
        
    public void writeHistoire(String fileName){
        FileOutputStream fos; 
        DataOutputStream dos;
        try {

            File file= new File(fileName+".log");
            fos = new FileOutputStream(file);
            dos=new DataOutputStream(fos);
            //dos.writeInt(2333);
            String txt = mesAgents.elementAt(0).getHistoire();
            dos.writeChars("Histoire de mon agent : \n "+ txt);

            System.out.println("!!! log file <"+ fileName +"> Written !!!");
        } catch (IOException e) {
            e.printStackTrace();
        }
   } 
    
    public static void writeHistoireFormatee(int numAgent, String path){
        FileOutputStream fos;
        try {
            fos = new FileOutputStream(new File(path));
            Agent ag = Controleur.mesAgents.elementAt(numAgent);
            for (int i=1; i<ag.getHistoireAgent().size()-1; i++){
                LogAgent prec = ag.getHistoireAgent().elementAt(i-1);
                LogAgent current = ag.getHistoireAgent().elementAt(i);
                if (prec.getX()==current.getX() && prec.getY()==current.getY()){
                    if(prec.getRessource()!=0){
                        //L'agent vient de poser une ressource
                        fos.write(("r"+prec.getRessource()+":").getBytes());
                    }
                    else{
                        //L'agent vient de prendre une ressource
                        fos.write(("r"+current.getRessource()+":").getBytes());
                    }
                }
                else{
                    fos.write("--:".getBytes());
                }
            }
            if (!(ag.getHistoireAgent().size()<=1)){
            LogAgent prec = ag.getHistoireAgent().elementAt(ag.getHistoireAgent().size()-2);
            LogAgent current = ag.getHistoireAgent().elementAt(ag.getHistoireAgent().size()-1);
            if (prec.getX()==current.getX() && prec.getY()==current.getY()){
                if(prec.getRessource()!=0){
                    //L'agent vient de poser une ressource
                    fos.write(("r"+prec.getRessource()).getBytes());
                }
                else{
                    //L'agent vient de prendre une ressource
                    fos.write(("r"+current.getRessource()).getBytes());
                }
            }
            else{
                fos.write("--".getBytes());
            }
            }
        } catch (Exception ex) {
            Logger.getLogger(Controleur.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
   
    
    public static synchronized Controleur getInstance() {
        if(controleur == null){
            controleur = new Controleur();
	}
        return controleur;
    }
    
    public static synchronized Controleur getInstance(boolean reinit, int nbAgents, int nbRessources,
                                                      boolean priseRessources, int nbStep, int delai, boolean periss,
                                                      boolean champAttractif, boolean enablePheromones, boolean disparitionPheromones,
                                                      int lifespanPheromones, boolean pheromonesAttractives) {
        if(controleur == null){
            controleur = new Controleur();
        }
        if (reinit){
            reinit(nbAgents, nbRessources, priseRessources, nbStep, delai, periss, champAttractif, enablePheromones, disparitionPheromones, lifespanPheromones, pheromonesAttractives);
        }
	return controleur;
    }
    
    public static synchronized void setVitesse(int delai){
        Controleur.delai = delai;
    }
  
}
